/*
 * (C) Copyright IBM Corp. 2004, 2005
 * Copyright (c) 2005, Intel Corporation
 * Copyright (c) 2005, University of New Hampshire
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place - Suite 330, Boston, MA 02111-1307 USA.
 *
 * Author(s):
 *     Kevin Gao <kevin.gao@intel.com>
 *     Carl McAdams <carlmc@us.ibm.com>
 *     Donald A. Barre <dbarre@unh.edu>
 *
 * Spec:        HPI-B.01.01
 * Function:    saHpiSensorEnableSet
 * Description:   
 *   Change a sensor enable status,
 *   to check if there's an event generated
 * Line:        P86-27:P86-27
 */

#include <stdio.h>
#include <string.h>
#include "saf_test.h"

#define MAX_SENSORS 2000
#define POLL_COUNT 10  // poll for events after every "n" sensors

static int sensorCount;

typedef struct {
    SaHpiResourceIdT resourceId;
    SaHpiSensorNumT sensorNum;
    SaHpiBoolT enabled;
    SaHpiBoolT foundEvent;
} SensorData;

static SensorData sensorData[MAX_SENSORS];

/**********************************************************************************
 *
 * Initialize a threshold structure.
 *
 **********************************************************************************/

void restoreSensors(SaHpiSessionIdT sessionId) {
    int       i;
    SaErrorT  status;

    for (i = 0; i < sensorCount; i++) {
        status = saHpiSensorEnableSet(sessionId, sensorData[i].resourceId,
                                      sensorData[i].sensorNum, sensorData[i].enabled);
        if (status != SA_OK) {
                e_print(saHpiSensorEnableSet, SA_OK, status);
        }
    }
}

int verifyEvents() {
    int  i;
    int  retval = SAF_TEST_PASS;

    for (i = 0; i < sensorCount; i++) {
            if (!sensorData[i].foundEvent) {
                    retval = SAF_TEST_FAIL;
                    m_print("Did not get an sensor change event from [resource: %d; sensor num: %d]", 
                             sensorData[i].resourceId, sensorData[i].sensorNum);
            }
    }

    return retval;
}

/**********************************************************************************
 *
 * Can we run this test?  The requirements are:
 *
 *      1) Must be a sensor.
 *      2) Must not have exceeded the number of sensors we are allowed to test.
 *
 **********************************************************************************/

int canTest(SaHpiSessionIdT sessionId,
            SaHpiResourceIdT resourceId, SaHpiRdrT * rdr)
{
        SaErrorT status;
        int retval = SAF_TEST_NOTSUPPORT;
        SaHpiSensorRecT *sensorRec;

        if (rdr->RdrType == SAHPI_SENSOR_RDR) {

                sensorRec = &(rdr->RdrTypeUnion.SensorRec);

                if ((sensorCount < MAX_SENSORS) && (sensorRec->EnableCtrl)) {
					retval = SAF_TEST_PASS;
                }
        }

        return retval;
}

/**********************************************************************************
 *
 * Check for any events that may have been mistakenly generated by the sensors.
 *
 **********************************************************************************/

int checkForEvents(SaHpiSessionIdT sessionId)
{
    int i;
    int retval = SAF_TEST_PASS;
    SaErrorT status;
    SaHpiEventT event;
    SaHpiSensorNumT sensorNum;

    while (SAHPI_TRUE) {
         status = saHpiEventGet(sessionId, SAHPI_TIMEOUT_IMMEDIATE, &event, NULL, NULL, NULL);
         if (status == SA_ERR_HPI_TIMEOUT) {
              break;
         } else if (status != SA_OK) {
              retval = SAF_TEST_UNRESOLVED;
              e_print(saHpiEventGet, SA_OK, status);
              break;
         } else if (event.EventType == SAHPI_ET_SENSOR_ENABLE_CHANGE) {
              sensorNum = event.EventDataUnion.SensorEnableChangeEvent.SensorNum;
              for (i = 0; i < sensorCount; i++) {
                  if ((sensorData[i].resourceId == event.Source) &&
                      (sensorData[i].sensorNum == sensorNum)) {
                      sensorData[i].foundEvent = SAHPI_TRUE;
                  }
              }
         }
    }

    return retval;
}

/**********************************************************************************
 *
 * Test an RDR.  If we can run the test, we will do so.  Note that if the sensor
 * is already disabled, we can simply run the test.  If it is enabled,
 * we will disable it and then run the test.
 *
 **********************************************************************************/

int testSensor(SaHpiSessionIdT sessionId, SaHpiResourceIdT resourceId, SaHpiRdrT *rdr)
{
        SaErrorT status;
        int retval = SAF_TEST_NOTSUPPORT;
        SaHpiBoolT sensorEnabled;
        SaHpiSensorRecT *sensorRec = &(rdr->RdrTypeUnion.SensorRec);

        status = saHpiSensorEnableGet(sessionId, resourceId, 
                                      sensorRec->Num, &sensorEnabled);
        if (status != SA_OK) {
                retval = SAF_TEST_UNRESOLVED;
                e_print(saHpiSensorEnableGet, SA_OK, status);
        } else {

                status = saHpiSensorEnableSet(sessionId, resourceId,
                                              sensorRec->Num, !sensorEnabled);
                if (status != SA_OK) {
                    retval = SAF_TEST_UNRESOLVED;
                    e_print(saHpiSensorEnableGet, SA_OK, status);
                } else {
					retval = SAF_TEST_PASS;
                    sensorData[sensorCount].resourceId = resourceId;
                    sensorData[sensorCount].sensorNum = sensorRec->Num;
                    sensorData[sensorCount].enabled = sensorEnabled;
                    sensorData[sensorCount].foundEvent = SAHPI_FALSE;
                    sensorCount++;
                }
        }

        if (retval == SAF_TEST_PASS && sensorCount % POLL_COUNT == 0) {
            retval = checkForEvents(sessionId);
        }

        return retval;
}

/**********************************************************************************
 *
 * Test a resource.
 *
 **********************************************************************************/

int testResource(SaHpiSessionIdT sessionId, SaHpiResourceIdT resourceId) {
     int retval = SAF_TEST_NOTSUPPORT;
     int response;
     SaErrorT error;
     SaHpiEntryIdT nextEntryId;
     SaHpiEntryIdT entryId;
     SaHpiRdrT rdr;
     SaHpiBoolT pass = SAHPI_FALSE;

     nextEntryId = SAHPI_FIRST_ENTRY;
     while (nextEntryId != SAHPI_LAST_ENTRY && retval == SAF_TEST_NOTSUPPORT) {
          entryId = nextEntryId;
          error = saHpiRdrGet(sessionId, resourceId, entryId, &nextEntryId, &rdr);
          if (error == SA_ERR_HPI_NOT_PRESENT) {
              break;
          } else if (error != SA_OK) {
              retval = SAF_TEST_UNRESOLVED;
              e_print(saHpiRdrGet, SA_OK, error);
          } else {
              response = canTest(sessionId, resourceId, &rdr);
              if (response != SAF_TEST_PASS) {
                   retval = response;
              } else {
                   response = testSensor(sessionId, resourceId, &rdr);
                   if (response == SAF_TEST_PASS) {
                       pass = SAHPI_TRUE;
                   } else {
                       retval = response;
                   }
              }
          }
     }

     if (retval == SAF_TEST_NOTSUPPORT && pass) {
         retval = SAF_TEST_PASS;
     }

     return retval;
}

/**********************************************************************************
 *
 * Test a domain.
 *
 **********************************************************************************/

int TestDomain(SaHpiSessionIdT sessionId)
{
     int retval = SAF_TEST_NOTSUPPORT;
     int response;
     SaErrorT error;
     SaHpiEntryIdT nextEntryId;
     SaHpiEntryIdT entryId;
     SaHpiRptEntryT rptEntry;
     SaHpiBoolT pass = SAHPI_FALSE;

     sensorCount = 0;
     error = saHpiSubscribe(sessionId);
     if (error != SA_OK) {
         e_print(saHpiSubscribe, SA_OK, error);
         retval = SAF_TEST_UNRESOLVED;
     } else {
         nextEntryId = SAHPI_FIRST_ENTRY;
         while (nextEntryId != SAHPI_LAST_ENTRY && retval == SAF_TEST_NOTSUPPORT) {
              entryId = nextEntryId;
              error = saHpiRptEntryGet(sessionId, entryId, &nextEntryId, &rptEntry);
              if (error == SA_ERR_HPI_NOT_PRESENT) {
                  break;
              } else if (error != SA_OK) {
                  retval = SAF_TEST_UNRESOLVED;
                  e_print(saHpiRptEntryGet, SA_OK, error);
              } else if (rptEntry.ResourceCapabilities & SAHPI_CAPABILITY_SENSOR) {
                  response = testResource(sessionId, rptEntry.ResourceId);
                  if (response == SAF_TEST_PASS) {
                      pass = SAHPI_TRUE;
                  } else {
                      retval = response;
                  }
              }
         }

         if (retval == SAF_TEST_NOTSUPPORT && pass) {
             // Check for any remaining events that may have been generated.
             // We will pause for 5 seconds to give the last sensor time to
             // generate an event.

             sleep(5);
             retval = checkForEvents(sessionId);

             if (retval == SAF_TEST_PASS) {
                 retval = verifyEvents();
             }
         }

         restoreSensors(sessionId);

         error = saHpiUnsubscribe(sessionId);
         if (error != SA_OK) {
              e_print(saHpiUnsubscribe, SA_OK, error);
         }
     }

     return retval;
}

/**********************************************************************************
 *
 * Main Program 
 *
 **********************************************************************************/

int main()
{
     return process_all_domains(NULL, NULL, TestDomain);
}

